#pragma once
#include <vector>

class FileHandler;

// constant for application specific error code
static const DWORD kErrorCodeBiggerThanApiCanManage = (1 << 29) + 0;
static const DWORD kErrorCodeIllegalCharacters = (1 << 29) + 1;

class CopyConverter
{

	DWORD mLastError;

	//---------------
protected:
	HGLOBAL mDataHandle;
	SIZE_T mDataHandleSize;
	SIZE_T mCurrentPos;
	SIZE_T mClipboardSize;

public:
	CopyConverter();
	~CopyConverter();

	// returns the (low) estimate of the data to be written to clipboard 
	virtual bool InitWithSelectionLength(LONGLONG selectionLength,
		LONGLONG& outMinDataLength, LONGLONG& outMaxDataLength) = 0;

	virtual int GetEstimatedBytesPerLine() const = 0;
	virtual LONGLONG GetWrittenDataLength() const;

	enum ErrorCode { kOk = 0, kWriteFail, kBadCharacter, kIncompleteCharacter,
		kNullCharacter};
	virtual ErrorCode WriteData(const BYTE* ptr, int& ioByteCount) = 0;

	// completes writing to data and tranfers ownership of the handle
	// with written data (and makes cleanup)
	virtual HGLOBAL GiveData() = 0;

	virtual bool IsWideCharacterData() const;

protected:
	bool CreateDataHandle(LONGLONG size);
	bool WriteTerminatingZero();

	virtual BYTE* GetBufferOfSize(int size) = 0;
	virtual void SaveUpToBufferOffset(int offset) = 0;
public:

};

class CopyConverterFixed : public CopyConverter
{
	BYTE* mDataPtr;
public:
	virtual bool InitWithSelectionLength(LONGLONG selectionLength,
		LONGLONG& outMinDataLength, LONGLONG& outMaxDataLength);
	virtual HGLOBAL GiveData();
protected:
	virtual LONGLONG CalculateDataLength(LONGLONG inputLength) const = 0;

	virtual BYTE* GetBufferOfSize(int size);
	virtual void SaveUpToBufferOffset(int offset);	
};

class CopyConverterExpandable : public CopyConverter
{
protected:
	const int kBlockSize = 0x4000;
	HANDLE mHeap;
	std::vector<BYTE*> mMemoryBlocks;
	size_t mCountOfUsedBlocks;
	int mPositionInLastBlock;
	bool mWasBlockWrittenOutOfPlace;
	//
public:
	virtual HGLOBAL GiveData();
protected:
	~CopyConverterExpandable();

	bool InitBuffersForSizes(LONGLONG minSize, LONGLONG maxSize);

	BYTE* GetBufferOfSize(int size);
	void SaveUpToBufferOffset(int offset);
	
};

class CopyConverterWysiwyg : public CopyConverterFixed
{
	LONGLONG mStartAddress;
public:
	CopyConverterWysiwyg(LONGLONG startAddress);

	virtual LONGLONG CalculateDataLength(LONGLONG inputLength) const;

	virtual int GetEstimatedBytesPerLine() const;
	virtual ErrorCode WriteData(const BYTE* ptr, int& ioByteCount);
};

class CopyConverterHexDigits : public CopyConverterFixed
{
public:

	virtual LONGLONG CalculateDataLength(LONGLONG inputLength) const;
	virtual int GetEstimatedBytesPerLine() const;
	virtual ErrorCode WriteData(const BYTE* ptr, int& ioByteCount);
};

class CopyConverterCStyleAscii : public CopyConverterExpandable
{
public:
	virtual bool InitWithSelectionLength(LONGLONG selectionLength,
		LONGLONG& outMinDataLength, LONGLONG& outMaxDataLength);

	virtual int GetEstimatedBytesPerLine() const;
	virtual ErrorCode WriteData(const BYTE* ptr, int& ioByteCount);
};

class CopyConverterUtf8 : public CopyConverterExpandable
{
	char32_t mCharacter;
	int mRemainingCount;
	int mCount;
public:
	virtual bool InitWithSelectionLength(LONGLONG selectionLength,
		LONGLONG& outMinDataLength, LONGLONG& outMaxDataLength);

	virtual int GetEstimatedBytesPerLine() const;
	virtual ErrorCode WriteData(const BYTE* ptr, int& ioByteCount);
	virtual bool IsWideCharacterData() const;
};

class CopyConverterUtf16Base : public CopyConverterFixed
{
	int mIndex;
	BYTE mPreviousByte;
	bool mWasFirstSurrogate;
public:
	CopyConverterUtf16Base();
	virtual LONGLONG CalculateDataLength(LONGLONG inputLength) const;
	virtual int GetEstimatedBytesPerLine() const;
	virtual ErrorCode WriteData(const BYTE* ptr, int& ioByteCount);
	virtual bool IsWideCharacterData() const;
protected:
	virtual char16_t ComposeWord(BYTE b1, BYTE b2) = 0;
};

class CopyConverterUtf16LE : public CopyConverterUtf16Base
{
protected:
	virtual char16_t ComposeWord(BYTE b1, BYTE b2);
};

class CopyConverterUtf16BE : public CopyConverterUtf16Base
{
protected:
	virtual char16_t ComposeWord(BYTE b1, BYTE b2);
};